// 
//  Copyright © 2009 Jiří Zárevúcky <zarevucky.jiri@gmail.com>
// 
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Affero General Public License as
//  published by the Free Software Foundation, either version 3 of the
//  License, or (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Affero General Public License for more details.
// 
//  You should have received a copy of the GNU Affero General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
// 
// 



using System;

using Galaxium.Protocol.Xmpp.Library.Xml;

namespace Galaxium.Protocol.Xmpp.Library.Core
{
	public enum MsgType { Chat, Error, GroupChat, Headline, Normal }
	
	public class XmlMessageEventArgs: EventArgs
	{
		public XmlMessage Message { get; private set; }
		public XmlMessageEventArgs (XmlMessage message) { Message = message; }
	}
	
	public class XmlMessage: Stanza
	{
		public new MsgType Type {
			get {
				switch (base.Type) {
				case "chat":      return MsgType.Chat;
				case "groupchat": return MsgType.GroupChat;
				case "headline":  return MsgType.Headline;
				case "error":     return MsgType.Error;
				default:          return MsgType.Normal;
				}
			}
			set {
				base.Type = value == MsgType.Normal ? null : value.ToString ().ToLower ();
			}
		}
		
		public string Subject {
			get {
				var lang = System.Globalization.CultureInfo.CurrentCulture.IetfLanguageTag;
				return GetSubject (lang) ?? GetSubject (null);
			}
		}
		
		public void AppendSubject (string subject)
		{
			AppendTextChild ("subject", null, subject);
		}
		
		public void AppendSubject (string subject, string lang_id)
		{
			AppendChild (new Element (null, "subject", null, "xml:lang", lang_id).SetText (subject));
		}
		
		public string Body {
			get {
				var lang = System.Globalization.CultureInfo.CurrentCulture.IetfLanguageTag;
				return GetBody (lang) ?? GetBody (null);
			}
		}
		
		public void AppendBody (string body)
		{
			AppendTextChild ("body", null, body);
		}
		
		public void AppendBody (string body, string lang_id)
		{
			AppendChild (new Element (null, "body", null, "xml:lang", lang_id).SetText (body));
		}
		
		public string Thread {
			get { return GetTextChild ("thread", null); }
		}
		
		public void AppendThread (string thread)
		{
			AppendTextChild ("thread", null, thread);
		}
		
		public DateTime Received { get; private set; }
		
	//	public Element HtmlBody { get; private set; }
		
	//	public DataForm DataForm { get; private set; }
		
		public static XmlMessage Create (Element message)
		{
			switch (message ["type"]) {
				case "chat": return new ChatMessage (message);
				case "groupchat": return new MUCMessage (message);
				case "headline": return new Headline (message);
			//	case "error": return new MessageError (stream, message);
				default: return new XmlMessage (message);
			}
		}
		
		public XmlMessage ()
			:base ("message")
		{
		}
		
		public XmlMessage (Element elm)
			:base (elm)
		{
			if (elm.Name != "message")
				throw new ArgumentException ();
			Received = DateTime.Now;
		}

		public XmlMessage (MsgType type, JabberID jid, string thread, string subject, string body)
			:this ()
		{
			Type = type;
			To = jid;
			if (!String.IsNullOrEmpty (thread))
				AppendThread (thread);
			if (!String.IsNullOrEmpty (subject))
				AppendSubject (subject);
			if (!String.IsNullOrEmpty (body))
				AppendBody (body);
			Received = DateTime.Now;
		}

		public string GetSubject (string lang_id)
		{
			if (lang_id == null)
				return GetTextChild ("subject", null);

			foreach (var child in this.EachChild ("subject"/*, Namespaces.Client*/))
				if (child ["xml:lang"] == lang_id) return child.Text;
			
			return null;
		}
		
		public string GetBody (string lang_id)
		{
			if (lang_id == null)
				return GetTextChild ("body", null);
			
			foreach (var child in this.EachChild ("body"/*, Namespaces.Client*/))
				if (lang_id == null || child ["xml:lang"] == lang_id) return child.Text;
			
			return null;
		}

		public bool GetDelay (out DateTime timestamp, out JabberID source, out string reason)
		{
			try {
				var delay_elm = FirstChild ("delay", Namespaces.Delay);
				if (delay_elm != null) {
					timestamp = DateTime.Parse (delay_elm ["stamp"]).ToLocalTime ();
				}
				else {
					delay_elm = FirstChild ("x", Namespaces.OldDelay);
					
					if (delay_elm == null)
					throw new Exception ();
					
					var stamp = delay_elm ["stamp"];
					timestamp = new DateTime (Int32.Parse (stamp.Substring (0, 4)),
					                          Int32.Parse (stamp.Substring (4, 2)),
					                          Int32.Parse (stamp.Substring (6, 2)),
					                          Int32.Parse (stamp.Substring (9, 2)),
					                          Int32.Parse (stamp.Substring (12, 2)),
					                          Int32.Parse (stamp.Substring (15, 2)));
					timestamp = timestamp.ToLocalTime ();
				}
				
				source = (JabberID) delay_elm ["from"];
				reason = delay_elm.Text;
				return true;
			}
			catch {
				timestamp = DateTime.MinValue;
				source = null;
				reason = null;
				return false;
			}
		}
		
		//var form_elm = message.FirstChild ("x", Namespaces.DataForms);
		//	if (form_elm != null) {
		//		DataForm = new DataForm (form_elm, (DataFormSubmitArgs args) => {
		//			var msg = new XmlMessage (Source, Thread, null, null);
		//			msg.AppendChild (args.Form.ToXml (true));
		//			if (this is ChatMessage
		//			    && (this as ChatMessage).ChatState != ChatState.Unknown)
		//				msg.AppendChild (new Element ("active", Namespaces.ChatStates));
		//			Stream.Send (msg);
		//		});
		//	}
	}
}
